package net.cl.db.core;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.cl.db.CachedResultSet;
import net.cl.db.DBException;

public class CachedResultSetImpl implements CachedResultSet {

	private List<Map<String, Object>> body;
	private int index;
	private int size;
	private int columnCount;
	private String[] columnName;

	public CachedResultSetImpl(ResultSet rs) {
		if (rs == null)
			throw new NullPointerException();
		try {
			index = -1;
			if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {
				rs.last();
				size = rs.getRow();
				rs.beforeFirst();
				body = new ArrayList<Map<String, Object>>(size);
			} else
				body = new ArrayList<Map<String, Object>>();
			ResultSetMetaData rsmd = rs.getMetaData();
			columnCount = rsmd.getColumnCount();
			columnName = new String[columnCount];
			for (int i = 1; i <= columnCount; i++) {
				columnName[i - 1] = rsmd.getColumnName(i);
			}
			while (rs.next()) {
				Map<String, Object> row = new HashMap<String, Object>(columnCount);
				for (int i = 1; i <= columnCount; i++) {
					row.put(columnName[i - 1], rs.getObject(i));
				}
				body.add(row);
			}
			if (rs.getType() == ResultSet.TYPE_FORWARD_ONLY)
				size = body.size();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	@Override
	public boolean next() throws DBException {
		if (index < size - 1) {
			index++;
			return true;
		}
		return false;
	}

	@Override
	public boolean previous() throws DBException {
		if (index > -1) {
			index--;
			return true;
		}
		return false;
	}

	@Override
	public boolean first() throws DBException {
		if (size == 0)
			return false;
		index = 0;
		return true;
	}

	@Override
	public boolean last() throws DBException {
		if (size == 0)
			return false;
		index = size - 1;
		return true;
	}

	@Override
	public void beforeFirst() throws DBException {
		index = -1;
	}

	@Override
	public void afterLast() throws DBException {
		index = -2;
	}

	@Override
	public int getRow() throws DBException {
		return index;
	}

	@Override
	public int getRowCount() throws DBException {
		return size;
	}

	@Override
	public boolean absolute(int row) throws DBException {
		if (row > 0) {
			if (row > size)
				return false;
			index = row - 1;
			return true;
		} else if (row < 0) {
			if (Math.abs(row) > size)
				return false;
			index = size + row;
			return true;
		} else {
			beforeFirst();
			return true;
		}
	}

	@Override
	public String getString(int columnIndex) throws DBException {
		String columnName = this.columnName[columnIndex - 1];
		return getString(columnName);
	}

	@Override
	public String getString(String columnName) throws DBException {
		Map<String, Object> row = body.get(index);
		return row.get(columnName) == null ? null : row.get(columnName).toString();
	}

	@Override
	public int getColumnCount() throws DBException {
		return columnCount;
	}

	@Override
	public String getColumnName(int columnIndex) throws DBException {
		return columnName[columnIndex - 1];
	}

	@Override
	public String getTableName(int columnIndex) throws DBException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int getColumnType(int columnIndex) throws DBException {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public String getColumnTypeName(int columnIndex) throws DBException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean isLast() throws DBException {
		return index == size - 1;
	}

	@Override
	public boolean isFirst() throws DBException {
		return index == 0;
	}

}
